package me.bincker.formwork.web.test

import me.bincker.formwork.web.core.entity.BaseEntity
import me.bincker.formwork.web.utils.BeanUtils
import me.bincker.formwork.web.utils.DateFormatUtils
import org.springframework.data.domain.Pageable
import org.springframework.test.web.servlet.request.RequestPostProcessor
import java.util.*
import kotlin.reflect.full.memberProperties

object RequestPostProcessors {
    /**
     * 设置分页参数
     */
    fun setPageableParam(pageable: Pageable) = RequestPostProcessor { request ->
        request.addParameter("page", pageable.pageNumber.toString())
        request.addParameter("size", pageable.pageSize.toString())
        request.addParameter("sort", pageable.sort.joinToString { order ->
            order.property + "," + order.direction
        })
        return@RequestPostProcessor request
    }

    /**
     * 设置查询参数
     */
    fun setQueryParam(entity: BaseEntity?) = RequestPostProcessor { request ->
        if(entity == null) return@RequestPostProcessor request
        val stack = Stack<Pair<String, Any>>()
        stack.add(Pair("", entity))
        while(stack.isNotEmpty()){
            val item = stack.pop()
            val parentPath = item.first
            val entityItem = item.second
            entityItem::class.memberProperties.forEach { property->
                val value = property.call(entityItem) ?: return@forEach
                val path = if(parentPath.isEmpty()) property.name else parentPath + "." + property.name
                if(value is BaseEntity){
                    stack.push(Pair(path, value))
                    return@forEach
                }
                if(BeanUtils.isSimpleType(value::class)){
                    if(value is Date){
                        request.addParameter(path, DateFormatUtils.format(value))
                    }else{
                        request.addParameter(path, value.toString())
                    }
                }else{
                    if(value is Collection<*>){
//                        if(value::class.starProjectedType.arguments.first().type.)
                        val params = mutableListOf<String>()
                        for (v in value){
                            val childEntity = v ?: continue
                            val childEntityType = childEntity::class
                            if(BeanUtils.isSimpleType(childEntityType)){
                                if(childEntity is Date){
                                    params.add(DateFormatUtils.format(childEntity))
                                }else{
                                    params.add(childEntity.toString())
                                }
                            }else {
                                val idProperty = childEntity::class.memberProperties.find { p -> p.name == "id" }
                                        ?: continue
                                params.add(idProperty.call(childEntity)?.toString() ?: continue)
                            }
                        }
                        request.addParameter(path, *params.toTypedArray())
                    }else{
                        val idProperty = value::class.memberProperties.find { p -> p.name == "id" } ?: return@forEach
                        val id = idProperty.call(value)
                        if(id != null){
                            request.addParameter(path, id.toString())
                        }else{
                            stack.push(Pair(path, value))
                        }
                    }
                }
            }
        }
        request
    }
}